%%%-------------------------------------------------------------------
%%% @author chenlong
%%% @copyright (C) 2019, <COMPANY>
%%% @doc
%%%
%%% @end
%%% Created : 22. 三月 2019 9:53
%%%-------------------------------------------------------------------
-module(role_public_server).
-author("chenlong").

-behaviour(gen_server).

-include("common.hrl").
-include_lib("stdlib/include/ms_transform.hrl").

%% API
-export([start_link/0]).

%% gen_server callbacks
-export([init/1,
	handle_call/3,
	handle_cast/2,
	handle_info/2,
	terminate/2,
	code_change/3]).

-define(SERVER, ?MODULE).

-record(state, {}).

-export([loadRolePublic/1]).

-export([secondsTick/1]).

%%--------------------------------------------------------------------
%% @doc
%% Starts the server
%%
%% @end
%%--------------------------------------------------------------------
-spec(start_link() ->
	{ok, Pid :: pid()} | ignore | {error, Reason :: term()}).
start_link() ->
	gen_server:start_link({local, ?SERVER}, ?MODULE, [], []).

%%%===================================================================
%%% gen_server callbacks
%%%===================================================================

%%--------------------------------------------------------------------
%% @private
%% @doc
%% Initializes the server
%%
%% @spec init(Args) -> {ok, State} |
%%                     {ok, State, Timeout} |
%%                     ignore |
%%                     {stop, Reason}
%% @end
%%--------------------------------------------------------------------
-spec(init(Args :: term()) ->
	{ok, State :: #state{}} | {ok, State :: #state{}, timeout() | hibernate} |
	{stop, Reason :: term()} | ignore).
init([]) ->
	ets:new(?ETS_ROLE_PUBLIC,[{keypos,#ets_role_public.roleID},set,public,named_table,?ETS_CONCURRENCY]),
	timer_wheel:init(),
	timer_wheel:plan(util:now()+?ONE_HOUR_SECONDS,fun secondsTick/1),
	{ok, #state{}}.

%%--------------------------------------------------------------------
%% @private
%% @doc
%% Handling call messages
%%
%% @end
%%--------------------------------------------------------------------
-spec(handle_call(Request :: term(), From :: {pid(), Tag :: term()},
	State :: #state{}) ->
	{reply, Reply :: term(), NewState :: #state{}} |
	{reply, Reply :: term(), NewState :: #state{}, timeout() | hibernate} |
	{noreply, NewState :: #state{}} |
	{noreply, NewState :: #state{}, timeout() | hibernate} |
	{stop, Reason :: term(), Reply :: term(), NewState :: #state{}} |
	{stop, Reason :: term(), NewState :: #state{}}).
handle_call(_Request, _From, State) ->
	{reply, ok, State}.

%%--------------------------------------------------------------------
%% @private
%% @doc
%% Handling cast messages
%%
%% @end
%%--------------------------------------------------------------------
-spec(handle_cast(Request :: term(), State :: #state{}) ->
	{noreply, NewState :: #state{}} |
	{noreply, NewState :: #state{}, timeout() | hibernate} |
	{stop, Reason :: term(), NewState :: #state{}}).
handle_cast(_Request, State) ->
	{noreply, State}.

%%--------------------------------------------------------------------
%% @private
%% @doc
%% Handling all non call/cast messages
%%
%% @spec handle_info(Info, State) -> {noreply, State} |
%%                                   {noreply, State, Timeout} |
%%                                   {stop, Reason, State}
%% @end
%%--------------------------------------------------------------------
-spec(handle_info(Info :: timeout() | term(), State :: #state{}) ->
	{noreply, NewState :: #state{}} |
	{noreply, NewState :: #state{}, timeout() | hibernate} |
	{stop, Reason :: term(), NewState :: #state{}}).
handle_info(Info, State) ->
	try
		case Info of
			{?timer_wheel_tick, Sec} ->
				timer_wheel:work(Sec);
			{refPublic, PlayerID} ->%%刷新最新访问时间戳
				ets:update_element(?ETS_ROLE_PUBLIC,PlayerID,{#ets_role_public.lastRefTime,util:now()});
			{updatePublic, Role} ->
				ets:insert(?ETS_ROLE_PUBLIC,#ets_role_public{
					roleID = Role#role.roleID,
					roleName = Role#role.roleName,
					headurl = Role#role.headurl,
					lastRefTime = util:now()
				});
			_ ->
				?ERR("no match module = ~p, Info=~p", [?MODULE, Info])
		end
	catch
		_:Why:StackTrace ->
			?ERR("module handle_info Info=~p,Why=~p,StackTrace=~p", [?MODULE,Info, Why,StackTrace])
	end,
	{noreply, State}.

%%--------------------------------------------------------------------
%% @private
%% @doc
%% This function is called by a gen_server when it is about to
%% terminate. It should be the opposite of Module:init/1 and do any
%% necessary cleaning up. When it returns, the gen_server terminates
%% with Reason. The return value is ignored.
%%
%% @spec terminate(Reason, State) -> void()
%% @end
%%--------------------------------------------------------------------
-spec(terminate(Reason :: (normal | shutdown | {shutdown, term()} | term()),
	State :: #state{}) -> term()).
terminate(_Reason, _State) ->
	ok.

%%--------------------------------------------------------------------
%% @private
%% @doc
%% Convert process state when code is changed
%%
%% @spec code_change(OldVsn, State, Extra) -> {ok, NewState}
%% @end
%%--------------------------------------------------------------------
-spec(code_change(OldVsn :: term() | {down, term()}, State :: #state{},
	Extra :: term()) ->
	{ok, NewState :: #state{}} | {error, Reason :: term()}).
code_change(_OldVsn, State, _Extra) ->
	{ok, State}.


%%%===================================================================
%%% API
%%%===================================================================
%%return #ets_role_public{}
loadRolePublic(RoleID) ->
	Role = case db_sql:getRole(RoleID) of
		#role{}= Role0 ->
			Role0;
		_ -> #role{
			roleID = RoleID,
			roleName = "role_"++integer_to_list(RoleID),
			headurl = "https://wx.qlogo.cn/mmopen/vi_32/DYAIOgq83erft0xkiaveqpvoq3ttSjzkhBvI6pAVmrKXQcAKI81XUl70fHjdv1E4SsbwMlgwWzmGV4nURU5mTbQ/132"
		}
	end,
	RolePublic = #ets_role_public{
		roleID = Role#role.roleID,
		roleName = Role#role.roleName,
		headurl = Role#role.headurl,
		lastRefTime = util:now()
	},
	ets:insert(?ETS_ROLE_PUBLIC,RolePublic),
	RolePublic.

%%%===================================================================
%%% Internal functions
%%%===================================================================
secondsTick(Seconds) ->
	Now = Seconds,
	Match = ets:fun2ms(
		fun(#ets_role_public{lastRefTime = LastTime}) ->
			Now - LastTime >= ?ROLE_PUBLIC_DELETE_TIME
		end
	),
	%%检测是否有需要从ETS删除的对象
	DeleteCount = ets:select_delete(?ETS_ROLE_PUBLIC,Match),
	?INFO("ETS_ROLE_PUBLIC DeleteCount=~p",[DeleteCount]),
	timer_wheel:plan(Now+?ONE_HOUR_SECONDS,fun secondsTick/1),
	ok.
